import OAuth2Client from './oauth2-client'
import {extend,sleep} from "../base/base";
import {getTokenStatue} from './util'
import {OAuth2Token} from './oauth2-token';

/**
 * 获取认证字符串
 * @param config 一些配置信息
 *  config = {
 *     clientId: 'client', //客户端 id
 *     clientSecret: '123456', //客户端密码
 *     accessTokenUri: '/oauth/token', //获取 token url
 *     refreshTokenUri: '',  刷新 token url，如果没有设置，用 accessTokenUri
 *     scopes: ['AUTH','LIVE'],   // 权限范围
 *     grantType: 'client_credentials', //认证方式  client
 *  }
 */
export class OAuth2 {

    constructor(config) {
        this.config = extend(config);
        this.oauth2 = new OAuth2Client(config);
        // token value 对象
        // 获取存储的token
        var tokenData = this.config.loadToken && typeof this.config.loadToken == 'function' && this.config.loadToken()

        if(tokenData){
            var setTokenData = loadTokenData => {
                if(this._tokenData_compile){
                    //this._tokenData_compile 为 true，表示异步时间已越过2秒
                    //2秒之后加载出来的数据不处理
                    return;
                }
                this._tokenData_compile = true;//表示初始 token 加载完成
                //创建 token 对象
                var token = this.oauth2.createToken(loadTokenData.access_token,
                  loadTokenData.refresh_token,
                  loadTokenData.token_type,
                  loadTokenData);
                //设置 grantType 认证类型
                this.config.grantType = loadTokenData.type;
                //设置 token
                this._setToken(token)
            };
            if(tokenData.constructor == Promise){
                this._tokenData_isPromise = true;//表示异步加载 tokenData 数据
                tokenData.then(setTokenData)
                sleep(2000).then(()=>{
                    //2秒之后，强制设置数据加载完成，防止异步加载时间过长，导致app界面假死
                    this._tokenData_compile = true;//表示初始 token 加载完成
                });
            }
            else {
                // 根据存储的token的data创建token信息
                setTokenData(tokenData);
            }
        }

        // 认证信息，只读
        Object.defineProperty(this, "accessToken",{
            configurable: false,
            get: () => {
                return this._accessToken;
            }
        });
        // 认证信息，只读
        Object.defineProperty(this, "refreshToken",{
            configurable: false,
            get: () => {
                return this._refreshToken;
            }
        });

        // 得到用户ID，只有 get 属性，无 set 属性
        Object.defineProperty(this, "userId",{
            configurable: false,
            get: () => {
                return this.accessToken && this.accessToken.userId;
            }
        });
    }

    //设置认证方式password、mobile、client
    setGrantType(grantType) {
        if (grantType != this.config.grantType) {
            delete this.token;
             delete  this._accessToken
            this._setToken(undefined);
        }
        this.config.grantType = grantType;
    }

    // 保存token
    _setToken(token) {
        this.token = token;
        if (this.token && this.token.data) {
            this.token.data.type = this.config.grantType;

            //解析访问 token
            this._accessToken = token.data.access_token && OAuth2Token.parse(token.data.access_token);
            //解析刷新 token
            this._refreshToken = token.data.refresh_token && OAuth2Token.parse(token.data.refresh_token);
            //访问 token 过期时间
            this.token.expires = this._accessToken && this._accessToken.expires;
            //刷新 token 过期时间
            this.token.refreshExpires = this._refreshToken && this._refreshToken.expires;

            //访问 token 有效期时长
            this.token.expiresIn = this.token.data.expires_in
        }
        //保存 token 信息
        this.config.storeToken && typeof this.config.storeToken == 'function' && this.config.storeToken(this.token && this.token.data)
    }

    // 用户名,密码
    setAuthInfo(authInfo) {
        this.config.username = authInfo.username;
        this.config.password = authInfo.password;
        this.config.authInfo = authInfo;
    }

    //获取认证字符串
    async getAuth() {
        //如果是异步加载默认的 tokenData ，并且数据还没有加载完成
        //则睡眠 5 ms 后再试
        while(this._tokenData_isPromise && !this._tokenData_compile){
            //此处不会因为异步加载数据时间过长，或出错而导致死循环
            //在异步加载默认 tokenData 时，2秒后会强制异步加载完成
            await sleep(5);//睡眠 5 毫秒之后，再试
        }
        //当前 token 状态
        var tokenStatue = getTokenStatue(this.token);
        //如果 token 没有过期，则直接返回
        if('no_expires' == tokenStatue){
            return new Promise((resolve) => {
                resolve(this.token.data.token_type + " " + this.token.data.access_token);
            })
        }

        //如果 token 即将过期，则异步刷新 token
        if('about_to_expires' == tokenStatue){
            //token即将过期，异步刷新
            this._refreshTokenFun().then(token => {
                this._setToken(token);
            })
        }
        if('access_expires' == tokenStatue){
            //访问 token 过期，同步刷新 token
            this._setToken(await this._refreshTokenFun());
        }

        //如果没有 token 信息 或 刷新 token 已过期
        if(!this.token || 'refresh_expires' == tokenStatue){
            //根据当前的 config 中的信息同步获取 token
            this._setToken(await this._getTokenFun());
        }

        if (this.token && this.token.data) {
            //如果存在 token 信息
            return new Promise((resolve) => {
                resolve(this.token.data.token_type + " " + this.token.data.access_token);
            })
        }
        //返回空认证信息
        return new Promise((resolve) => {
            resolve();
        })
    }

    /**
     * 刷新token
     */
    async _refreshTokenFun() {
        // 认证方式为client，则没有刷新token，只有获取token
        if (this.config.grantType == 'client') {
            return this._getTokenFun();
        }
        return this.token.refresh().then((token) => {
            // return this._processToken(token)
            return token;
        }).catch(error => {
            console.log(error)
            return undefined;
        });
    }

    /**
     * 获取token
     */
    async _getTokenFun() {
        var tokenPromise = undefined;
        if (this.config.grantType == 'password') {
            // 用户名和密码
            tokenPromise = this.oauth2.owner.getToken(this.config.username, this.config.password)
        } else if(this.config.grantType == 'client'){
            // 客户端
            tokenPromise = this.oauth2.credentials.getToken()
        }else{
            //'mobile':短信认证
            tokenPromise = this.oauth2.extra.getToken(this.config.authInfo)
        }

        return tokenPromise

        // .then(token => {
        //     //return this._processToken(token)
        //     return token;
        // }).catch(function (e) {
        //     console.log(e)
        // });
    }

    hasRole(role) {
        return this.accessToken && this.accessToken.hasRole.apply(this.accessToken,arguments);
    }

    // 是否拥有其中一个角色
    hasAnyRole() {
        return this.accessToken && this.accessToken.hasAnyRole.apply(this.accessToken,arguments);
    }

    // 是否同时拥有所有角色
    hasAndRole() {
        return this.accessToken && this.accessToken.hasAndRole.apply(this.accessToken,arguments);
    }

    // 判断是否拥有某个权限,判断的权限为undefined或null或空字符串时，认为拥有权限
    hasAuthority(authority) {
        return this.accessToken && this.accessToken.hasAuthority.apply(this.accessToken,arguments);
    }

    // 是否拥有其中一个权限
    hasAnyAuthority() {
        return this.accessToken && this.accessToken.hasAnyAuthority.apply(this.accessToken,arguments);
    }

    // 是否同时拥有所有权限
    hasAndAuthority() {
        return this.accessToken && this.accessToken.hasAndAuthority.apply(this.accessToken,arguments);
    }

    // 表示是否通过password或mobile模式获取的token。
    isUser() {
        return this.accessToken && this.accessToken.isUser();
    }

    // 表示是否通过client模式获取的token。
    isClient() {
        return this.accessToken && this.accessToken.isClient();
    }
}
